// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-12-05

package message

import (
	"context"
	"encoding/json"
	"gitee.com/go-libs/log"
	"gitee.com/gomq/sr/name"
	"net/http"
	"sync"
	"time"
)

var (
	payloadPool = sync.Pool{
		New: func() interface{} {
			return &Payload{}
		},
	}
	payloadTime = time.Unix(0, 0)
)

// Payload is a component that store producer message attributes for
// servlet publisher to publish to given topics.
type Payload struct {
	Body         []byte         `json:"Body,omitempty"`
	DelaySeconds int            `json:"DelaySeconds,omitempty"`
	Hash         Hash           `json:"Hash,omitempty"`
	Header       http.Header    `json:"Header,omitempty"`
	Keyword      Keyword        `json:"Keyword,omitempty"`
	Tag          name.TopicTag  `json:"Tag,omitempty"`
	Time         time.Time      `json:"Time,omitempty"`
	Topic        name.TopicName `json:"Topic,omitempty"`
}

// NewPayload acquires an instance from pool, You must call Release()
// method to release it when done.
func NewPayload(ctx context.Context) *Payload {
	return payloadPool.
		Get().(*Payload).
		acquirer().
		acquirerWithContext(ctx)
}

// NewPayloadWithHeader acquires an instance from pool, You must call
// Release() method to release it when done.
func NewPayloadWithHeader(header http.Header) *Payload {
	return payloadPool.
		Get().(*Payload).
		acquirer().
		acquirerWithHeader(header)
}

// Release
// releases the payload instance into pool.
func (o *Payload) Release() {
	o.releaser()
}

// String
// converts the payload as json string.
func (o *Payload) String() string {
	if buf, err := json.Marshal(o); err == nil {
		return string(buf)
	}
	return "{}"
}

// + Access

func (o *Payload) acquirer() *Payload {
	o.Time, o.Hash = time.Now(), NewHash()
	return o
}

func (o *Payload) acquirerWithContext(ctx context.Context) *Payload {
	return o.acquirerWithHeader(log.ContextHeader(ctx))
}

func (o *Payload) acquirerWithHeader(header http.Header) *Payload {
	if header != nil && len(header) > 0 {
		o.Header = header
		return o
	}

	o.Header = make(http.Header)
	return o
}

func (o *Payload) releaser() {
	// o.Ctx, o.Header, o.Time, o.Hash = nil, nil, payloadTime, HashUndefined
	o.Header, o.Time, o.Hash = nil, payloadTime, HashUndefined
	o.Body, o.Keyword, o.DelaySeconds, o.Tag, o.Topic = nil, "", 0, "", ""
	payloadPool.Put(o)
}
